package top.kikt.book.core.base

import top.kikt.book.core.config.AppConfig
import top.kikt.book.core.entity.BookEntity
import top.kikt.book.core.entity.ChapterMetaEntity
import top.kikt.book.core.template.EpubTemplate
import top.kikt.book.core.template.TextTemplate
import java.io.File
import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.Future


/**
 * 核心类
 */
class BookGetter(
    private val url: String,
    val bookHandler: BookHandler,
    threadCount: Int = 12,
) : ILogger {

    private val threadPool = Executors.newFixedThreadPool(threadCount)

    private var tryStopSet = Collections.synchronizedSet(HashSet<Boolean>())

    fun tryStop() {
        tryStopSet.add(true)
    }

    /**
     * 调用这个方法就可以解析书了
     */
    fun parse(): BookEntity? {
        val document = bookHandler.getUrlDocument(url) ?: return null

        val bookMeta = bookHandler.createBookMetaHandler().parseBookMeta(document, url)

        val menuUrl = bookMeta.menuUrl

        if (menuUrl.trim().isEmpty()) {
            logger.info("menuUrl is null")
            logger.info("The bookHandler is null: {}", bookHandler)
            throw Exception("menuUrl is null")
        }

        val coverUrl = bookMeta.coverImageUrl
        if (coverUrl?.trim().isNullOrEmpty()) {
            logger.info("coverUrl is null")
            logger.info("The bookHandler is null: {}", bookHandler)
            throw Exception("coverUrl is null")
        }

        logger.info("meta信息如下:\n{}", bookMeta)

        val menuDocument = if (menuUrl == url) {
            document
        } else {
            bookHandler.getMenuDocument(menuUrl)
        } ?: return null

        val chapterMetaList = bookHandler.createBookChapterHandler().parseChapterMeta(menuDocument, bookMeta.menuUrl)

        return BookEntity(bookMeta, chapterMetaList)
    }

    /**
     * 通过读取 [bookHandler] 和 [appConfig] 的配置, 并将小说 [bookEntity] 所在的内容写入到文件内,
     */
    fun writeFile(bookHandler: IBookHandler, bookEntity: BookEntity, appConfig: AppConfig): List<File> {
        val host = bookHandler.host
        val bookOutput = bookHandler.getOutputPath()
        logger.info("The host = $host, 输出到 $bookOutput")
        val outputPath = appConfig.outputPath
        val tmpPath = appConfig.tmpPath ?: "$outputPath/tmp"
        val tmpDir = File("$tmpPath/$bookOutput/${bookEntity.metaEntity.name}")

        if (!tmpDir.exists()) {
            tmpDir.mkdirs()
        }

        val bookChapterHandler = this.bookHandler.createBookChapterHandler()
        logger.info("共有 : ${bookEntity.chapterMetaEntityList.count()} 个任务")

        logger.info("当前已有临时文件 ${tmpDir.listFiles()?.count() ?: 0} 个")

        var taskCount = 0

        val futures = Collections.synchronizedList(ArrayList<Future<*>>())

        val files = Collections.synchronizedMap(HashMap<ChapterMetaEntity, File>())
        bookEntity.files = files

        for (chapterMeta in bookEntity.chapterMetaEntityList) {
            val fileName = "$tmpDir/${chapterMeta.fileName()}"
            val file = File(fileName)

            if (file.exists()) { // 存在说明写入过了, 跳过
                files[chapterMeta] = file
                continue
            }
            taskCount++
            futures.add(threadPool.submit {
                if (tryStopSet.isNotEmpty()) {
                    return@submit
                }
                logger.info("${chapterMeta.name} ${chapterMeta.url} 准备请求")
                while (true) {
                    try {
                        val chapter = bookChapterHandler.parseChapter(chapterMeta) ?: return@submit
                        file.createNewFile()
                        file.writeText(chapter.text)
                        files[chapterMeta] = file
                        logger.info("${chapterMeta.name} 写入完毕")
                        break
                    } catch (e: Exception) {
                        logger.info("${chapterMeta.name} ${chapterMeta.url} 请求出错", e)
                    }
                }

            })
        }

        logger.info("当前共有任务 ${futures.count()} 个")

        for (future in futures) {
            future.get()
        }

        if (tryStopSet.isNotEmpty()) {
//            throw ThreadInterruptedException(RepImpl, "")
            logger.info("接收到退出信息，关闭")
            return emptyList()
        }


        val templates = arrayOf(
            TextTemplate(bookChapterHandler),
            EpubTemplate(),
        )

        val outputFiles = ArrayList<File>()

        for (template in templates) {
            val outputFile = template.write(bookHandler, bookEntity, outputPath)
            outputFiles.add(outputFile)
        }

        return outputFiles
    }

}

